#include <my_header.h>
#define BLOCK_SIZE (1024 * 1024 * 8)
/*Usage: ./03_mmapcp src dest  */
int main(int argc, char *argv[]){
    ARGS_CHECK(argc,3);
    int fds = open(argv[1],O_RDONLY);
    ERROR_CHECK(fds, -1,"open src");

    // 获取源文件的大小
    off_t src_size = lseek(fds, 0, SEEK_END);
    //从0开始的位置一直读取到末尾，获取文件的大小
    //为了使用占位确定文件复制是否可以成功

    //读写模式打开目标文件
    int fdw = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0666);
    ERROR_CHECK(fdw, -1, "open dest");  

    //设置占位文件
    int sret = ftruncate(fdw, src_size);
    ERROR_CHECK(sret, -1, "ftruncate error");

    /*使用memcpy进行文件的复制
     * memcpy(dest, src, 复制的字节大小);
     */
    //设置一个长度，记录复制的起始位置
    off_t byte = 0;
    //循环结束的条件设置为byte<src_size
    while(byte < src_size){
        //确定每次复制的字节大小
        off_t current_size = (byte + BLOCK_SIZE > src_size) ? 
            //如果已复制字节数加上一次复制的大小，超过了源文件的大小
            //说明这一次就是文件的最后一次复制，此时只需要映射后面的文件
            (src_size - byte) : 
            //到这里就是说明不是最后一次复制
            //那就继续映射一个块的大小
            BLOCK_SIZE;

        //映射源文件
        void *srcp = mmap(NULL, current_size,
                PROT_READ | PROT_WRITE, MAP_SHARED, fds, byte);
        ERROR_CHECK(srcp,MAP_FAILED,"srcp error");

        //映射目标文件
        void *destp = mmap(NULL, current_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdw, byte);
        ERROR_CHECK(destp, MAP_FAILED, "destp error");

        //开始文件复制（映射文件的复制）
        memcpy(destp, srcp, current_size);

        //复制完成解除映射
        munmap(srcp, current_size);
        munmap(destp, current_size);

        //更新已复制的字节数
        byte += current_size;
    }
    close(fds);
    close(fdw);
    return 0;
}

